#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "_icon.h"
#include "icon.h"
#include "image.h"
#include "window.h"

#ifdef __DEBUG__
#define __E(fmt, args...) fprintf(stderr, "ICON ERROR [%d]: " fmt, __LINE__, ## args)
#define __W(fmt, args...) fprintf(stderr, "ICON WARNING [%d]: " fmt, __LINE__, ## args)
#else
#define __E(fmt, args...)
#define __W(fmt, args...)
#endif

#define false               0
#define true                1

static icon icones[MAX_NUMBER_ICONS];
static int icId = 0;

int icon_create(unsigned int x, unsigned int y, unsigned char *image_on, unsigned char *image_off) {
    if (icId > MAX_NUMBER_ICONS) {
        __E("Nao e possivel criar mais botoes. Numero maximo.\n");
        return ICON_FAILURE;
    } else {
        icones[icId].x = x;
        icones[icId].y = y;
        icones[icId].selected = false;
        icones[icId].visible = true;
        icones[icId].initialized = false;
        icones[icId].id = icId;
        icones[icId].winp = NULL;
        icones[icId].previous = &icones[icId];
        icones[icId].next = &icones[icId];

        if ((icones[icId].image_on = image_create(x, y, image_on)) == IMAGE_FAILURE) {
            __E("Erro ao criar imagem do icone\n");
            return ICON_FAILURE;
        }
        
        if (image_setVisible(icones[icId].image_on, 0) == IMAGE_FAILURE) {
            __E("Falhou setar a visibilidade do icone selecionado.\n");
        }


        if ((icones[icId].image_off = image_create(x, y, image_off)) == IMAGE_FAILURE) {
            __E("Erro ao criar imagem do icone\n");
            return ICON_FAILURE;
        }

        if (image_setVisible(icones[icId].image_off, 1) == IMAGE_FAILURE) {
            __E("Falhou setar a visibilidade do icone nao selecionado.\n");
        }

        icones[icId].initialized = true;
        return icId++;
    }
}

signed int icon_destroy(signed int iconId) {
    if (!icones[iconId].initialized) {
        __E("Icone nao pode ser destruido: icone nao foi criado.");
        return ICON_FAILURE;
    }

    icones[iconId].x = 0;
    icones[iconId].y = 0;
    image_destroy(icones[iconId].image_on);
    icones[iconId].image_on = -1;
    image_destroy(icones[iconId].image_off);
    icones[iconId].image_off = -1;
    icones[iconId].selected = 0;

    icon_delFromWindow(iconId);
    icones[iconId].initialized = 0;
    return ICON_SUCCESS;
}

/* icon_draw desenha um icone no buffer da janela a que ele esta associado */
int icon_draw(int iconId) {
    if (icones[iconId].initialized) {
        if (icones[iconId].winp) {
            if (icones[iconId].visible) {

                int imageId = icones[iconId].selected ? icones[iconId].image_on : icones[iconId].image_off;

                if (image_draw(imageId) == IMAGE_FAILURE) {
                    __E("Nao foi possivel desenhar o icone (draw).\n");
                    return ICON_FAILURE;
                } else return ICON_SUCCESS;
            } else return ICON_SUCCESS;
        } else {
            __E("Nenhuma tela associada ao icone.\n");
            return ICON_FAILURE;
        }
    } else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_unselect(signed int iconId) {
    if (icones[iconId].initialized) {
        if (icones[iconId].winp) {
			if (icones[iconId].selected) {
	            icones[iconId].selected = 0;
		        window_set_actualIcon_selected(icones[iconId].windowId, -1);

				if (window_removeImage(icones[iconId].windowId, icones[iconId].image_on) == WINDOW_FAILURE) {
					__E("icon_select: Falha ao remover imagem icon_off\n");
					return ICON_FAILURE;
				}
	
				if (window_insertImage(icones[iconId].windowId, icones[iconId].image_off) == WINDOW_FAILURE) {
					__E("icon_select: Falha ao remover imagem icon_on\n");
					return ICON_FAILURE;
				}
				image_setVisible(icones[iconId].image_off, 1);
			}
            return ICON_SUCCESS;
        } else {
            __E("Nenhuma tela associada ao icone.\n");
            return ICON_FAILURE;
        }
    } else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_select(signed int iconId) {
    if (icones[iconId].initialized) {
        if (icones[iconId].winp) {
            signed int aux = window_inform_actualIcon(icones[iconId].windowId);
            if (aux < 0) return ICON_FAILURE;
            do {
                if (icones[aux].selected == 1) {
                    icon_unselect(aux);
                }
                aux = icon_next(aux);
            } while (aux != window_inform_actualIcon(icones[iconId].windowId));
            icones[iconId].selected = 1;

			if (window_removeImage(icones[iconId].windowId, icones[iconId].image_off) == WINDOW_FAILURE) {
				__E("icon_select: Falha ao remover imagem icon_off\n");
				return ICON_FAILURE;
			}

			if (window_insertImage(icones[iconId].windowId, icones[iconId].image_on) == WINDOW_FAILURE) {
				__E("icon_select: Falha ao remover imagem icon_on\n");
				return ICON_FAILURE;
			}

            image_setVisible(icones[iconId].image_on, 1);

            window_set_actualIcon_selected(icones[iconId].windowId, iconId);

            return ICON_SUCCESS;
        } else {
            __E("Nenhuma tela associada ao icone.\n");
            return ICON_FAILURE;
        }
    } else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

int icon_setVisible(int iconId, unsigned char visible) {
    if (icones[iconId].initialized) {
        if (icones[iconId].winp) {
            if (visible == true || visible == false) {
                icones[iconId].visible = visible;
                return ICON_SUCCESS;
            } else {
                __E("Opcao invalida.\n");
                return ICON_FAILURE;
            }
        } else {
            __E("Nenhuma tela associada ao icone.\n");
            return ICON_FAILURE;
        }
    } else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

int icon_addToWindow(int iconId, int iconId_next, int windowId, window *winp) {
    if (icones[iconId_next].winp == NULL) {
        icones[iconId_next].next = icones[iconId].next;
        icones[iconId].next = &icones[iconId_next];
        icones[iconId_next].previous = &icones[iconId];
        icones[iconId_next].next->previous = &icones[iconId_next];
        icones[iconId_next].winp = winp;
        icones[iconId_next].windowId = windowId;

        if (window_insertImage(windowId, icones[iconId_next].image_off) == WINDOW_FAILURE) {
            __E("Erro ao inserir imagem do icone\n");
            return WINDOW_FAILURE;
        }

		if (image_setVisible(icones[iconId_next].image_off, 1) == IMAGE_FAILURE) {
			__E("Erro ao setar a visibilidade do ícone não selecionado.\n");
		}
        return ICON_SUCCESS;
    } else {
        __E("Ja existe uma tela associada ao icone.\n");
        return ICON_FAILURE;
    }
}

signed int icon_delFromWindow(signed int iconId) {
    if (!icones[iconId].initialized) {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }

    if (icones[iconId].winp == NULL) {
        return ICON_SUCCESS;
    }

    if (icones[iconId].next == &icones[iconId]) {
        icones[iconId].winp->firstIcon = -1;
        icones[iconId].winp->actualIcon = -1;
    } else {
        if (icones[iconId].winp->actualIcon == iconId) {
            icones[iconId].winp->actualIcon = icones[icones[iconId].winp->actualIcon].previous->id;
        } else if (icones[iconId].winp->firstIcon == iconId) {
            icones[iconId].winp->firstIcon = icones[icones[iconId].winp->firstIcon].next->id;
        }

        icones[iconId].previous->next = icones[iconId].next;
        icones[iconId].next->previous = icones[iconId].previous;
    }

    if (icones[iconId].winp->actualIcon_selected == icones[iconId].id) {
        icones[iconId].winp->actualIcon_selected = -1;
    }

    window_removeImage(icones[iconId].windowId, icones[iconId].image_on);
    window_removeImage(icones[iconId].windowId, icones[iconId].image_off);

    icones[iconId].previous = &icones[iconId];
    icones[iconId].next = &icones[iconId];
    icones[iconId].winp = NULL;
    icones[iconId].windowId = -1;
    window_setComponentsRedraw(icones[iconId].windowId);
    return ICON_SUCCESS;
}

int icon_read(int iconId) {
    if (icones[iconId].initialized) return icones[iconId].selected;
    else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_isSelected(signed int iconId) {
    if (icones[iconId].initialized) {
        return icones[iconId].selected;
    } else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

int icon_previous(int iconId) {
    if (icones[iconId].initialized) return icones[iconId].previous->id;
    else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

int icon_next(int iconId) {
    if (icones[iconId].initialized) return icones[iconId].next->id;
    else {
        __E("Icone nao criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_getX(signed int iconId) {
    if (icones[iconId].initialized) {
        return icones[iconId].x;
    } else {
        __E("Ícone não foi criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_getY(signed int iconId) {
    if (icones[iconId].initialized) {
        return icones[iconId].y;
    } else {
        __E("Ícone não foi criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_getWidth(signed int iconId) {
    if (icones[iconId].initialized) {
        return image_getWidth(icones[iconId].image_off) > image_getWidth(icones[iconId].image_on) ?
                image_getWidth(icones[iconId].image_off) :
                image_getWidth(icones[iconId].image_on);
    } else {
        __E("Ícone não foi criado.\n");
        return ICON_FAILURE;
    }
}

signed int icon_getHeight(signed int iconId) {
    if (icones[iconId].initialized) {
        return image_getHeight(icones[iconId].image_off) > image_getWidth(icones[iconId].image_on) ?
                image_getHeight(icones[iconId].image_off) :
                image_getHeight(icones[iconId].image_on);
    } else {
        __E("Ícone não foi criado.\n");
        return ICON_FAILURE;
    }
}
